package searchlogic

import (
	"strings"
)

type SearchResultItem struct {
	TitleHasKeyword       bool
	TitleKeywordPosFrom   int
	TitleKeywordPosTo     int
	ContentHasKeyword     bool
	ContentKeywordPosFrom int
	ContentKeywordPosTo   int
	MapInfo               *MindMapInfo
}

type BaseSearcherStruct struct {
	// 匹配方式：true-找匹配的，false-找不匹配的
	SearchMatched bool

	// 关键词
	Keyword string

	// 引号数量：
	// 0 - abc
	// 1 - "abc
	// 2 - "abc"
	QuotCnt int
}

type ExpSearcher interface {
	DoMatch(mapInfo *MindMapInfo) *SearchResultItem
}

type TagExpSearcher struct {
	BaseSearcherStruct
	Wild bool
}

func baseSearch(str string, keyword string) (bool, int, int) {
	str = strings.ToLower(str)
	keyword = strings.ToLower(keyword)

	tmp := strings.Index(str, keyword)
	if tmp >= 0 {
		from := tmp
		to := from + len(keyword)
		return true, from, to
	}
	return false, -1, -1
}

func (s *TagExpSearcher) DoMatch(mapInfo *MindMapInfo) *SearchResultItem {
	kwLowerTrim := strings.TrimSpace(strings.ToLower(s.Keyword))
	for _, eachTag := range mapInfo.Tags {
		eachTagLowerTrim := strings.TrimSpace(strings.ToLower(eachTag))
		match := (s.Wild && strings.Contains(eachTagLowerTrim, kwLowerTrim)) || (!s.Wild && eachTagLowerTrim == kwLowerTrim)

		if (s.SearchMatched && match) || (!s.SearchMatched && !match) {
			return &SearchResultItem{
				MapInfo: mapInfo,
			}
		}
	}
	return nil
}

type TitleExpSearcher struct {
	BaseSearcherStruct
}

func (s *TitleExpSearcher) DoMatch(mapInfo *MindMapInfo) *SearchResultItem {
	match, from, to := baseSearch(mapInfo.Title, s.Keyword)

	if s.SearchMatched {
		if !match {
			return nil
		}
		return &SearchResultItem{
			MapInfo:             mapInfo,
			TitleHasKeyword:     true,
			TitleKeywordPosFrom: from,
			TitleKeywordPosTo:   to,
		}
	}

	if match {
		return nil
	}
	return &SearchResultItem{
		MapInfo: mapInfo,
	}
}

type FullTxtExpSearcher struct {
	BaseSearcherStruct
}

func (s *FullTxtExpSearcher) DoMatch(mapInfo *MindMapInfo) *SearchResultItem {
	titleMatch, from1, to1 := baseSearch(mapInfo.Title, s.Keyword)
	contMatch, from2, to2 := baseSearch(mapInfo.Content, s.Keyword)

	// 要查找匹配的，只要标题内容任意一个有匹配即可算作匹配
	if s.SearchMatched {
		if !titleMatch && !contMatch {
			return nil
		}
		result := &SearchResultItem{
			MapInfo: mapInfo,
		}
		if titleMatch {
			result.TitleHasKeyword = true
			result.TitleKeywordPosFrom = from1
			result.TitleKeywordPosTo = to1
		}
		if contMatch {
			result.ContentHasKeyword = true
			result.ContentKeywordPosFrom = from2
			result.ContentKeywordPosTo = to2
		}
		return result
	}

	// 查找不匹配，只有标题内容都不匹配才算匹配
	if titleMatch || contMatch {
		return nil
	}
	return &SearchResultItem{
		MapInfo: mapInfo,
	}
}

type ContentExpSearcher struct {
	BaseSearcherStruct
}

func (s *ContentExpSearcher) DoMatch(mapInfo *MindMapInfo) *SearchResultItem {
	match, from, to := baseSearch(mapInfo.Content, s.Keyword)
	if s.SearchMatched {
		if !match {
			return nil
		}
		return &SearchResultItem{
			MapInfo:               mapInfo,
			ContentHasKeyword:     true,
			ContentKeywordPosFrom: from,
			ContentKeywordPosTo:   to,
		}
	}

	if match {
		return nil
	}
	return &SearchResultItem{
		MapInfo: mapInfo,
	}
}
